import { cloneDeep, get, merge as mergeObj } from 'lodash'

const handlerComFn = async (fn, data) => {
  if (fn && typeof fn === 'function') {
    try {
      return await fn(data)
    } catch (error) {
      console.error(error)
      return Promise.reject(error)
    }
  }
  return data
}

/**
 *  新增和修改Hooks
 * @param {object} options
 * @returns
 */
export const useAddEditHook = (options) => {
  const { proxy } = getCurrentInstance()

  const {
    // 模块名称
    moduleName = '模块',
    // 模块主键
    primaryKey = 'id',
    // 表单初始值
    initForm = {},
    // 表单验证规则
    rules = {},
    // api请求配置
    apiFnConfig = {
      add: null, // 添加
      edit: null, // 修改
      info: null // 详情
    },
    handlerConfig = {
      /**
       * 弹窗打开之前(新增在打开弹框之前，修改在回显请求之前)
       */
      beforeOpenFn: null,
      /**
       * 弹窗打开之后(在设置弹框变量true之后)
       */
      afterOpenFn: null,
      /**
       * 修改请求数据之前(作用：对提交数据做一些处理)
       * @param rowData 调用open方法传入的数据
       * @returns object|boolean  如果返回false会阻止请求
       */
      beforeInfoFn: null,
      /**
       * 修改请求数据之后(作用：对提交数据做一些处理再赋给表单)
       * @param responseData 后端返回的数据
       * @returns object|boolean  如果返回false会阻止赋值
       */
      afterInfoFn: null,
      /**
       * 提交数据之前
       * @param formData 表单的数据信息
       * @returns object|boolean  如果返回false会阻止提交
       */
      beforeSubmitFn: null,
      /**
       * 提交数据之后
       * @param responseData 后端返回的数据
       * @returns object|boolean  如果返回false会阻止赋值
       */
      afterSubmitFn: null,
      /**
       * 弹窗关闭之前
       * @returns any|boolean  如果返回false会阻止赋值
       *
       */
      beforeCloseFn: null,
      /**
       * 弹窗关闭之后
       *
       */
      afterCloseFn: null
    }
  } = options
  const gFormInstance = ref(null)
  const data = reactive({
    gConfirmLoading: false,
    gTitle: '',
    gVisible: false,
    gFormData: cloneDeep(initForm),
    gFormRule: cloneDeep(rules)
  })
  const { gFormData, gFormRule, gConfirmLoading, gVisible, gTitle } = toRefs(data)
  const gIsEdit = computed(() => !!gFormData.value[primaryKey])

  // 打开弹框
  const gOpen = async (row) => {
    let beforeOpenResult = await handlerComFn(handlerConfig.beforeOpenFn, row)
    if (beforeOpenResult === false) return
    if (!row || !row[primaryKey]) {
      gVisible.value = true
      await handlerComFn(handlerConfig.afterOpenFn)
      return (gTitle.value = `新增${moduleName}`)
    }
    if (!apiFnConfig.info || typeof apiFnConfig.info !== 'function') {
      return console.error('apiFnConfig的info属性未配置api函数')
    }
    let requestData = await handlerComFn(handlerConfig.beforeInfoFn, row)
    if (requestData === false) return
    apiFnConfig.info(requestData).then(async (response) => {
      const responseData = await handlerComFn(handlerConfig.afterInfoFn, response.data)
      if (responseData === false) return
      gFormData.value = responseData
      gTitle.value = `修改${moduleName}`
      gVisible.value = true
      await handlerComFn(handlerConfig.afterOpenFn, responseData)
    })
  }
  // 关闭弹框
  const gClose = async () => {
    const result = await handlerComFn(handlerConfig.beforeCloseFn)
    if (result === false) return
    gVisible.value = false
    gFormData.value = cloneDeep(initForm)
    // 兼容 plus-pro-form
    if (gFormInstance.value.formInstance) {
      gFormInstance.value.formInstance.resetFields()
    } else {
      gFormInstance.value.resetFields()
    }
    handlerComFn(handlerConfig.afterCloseFn)
  }

  // 提交事件
  const gSubmitForm = async () => {
    try {
      // 兼容 plus-pro-form
      let isValid = false
      if (gFormInstance.value.handleSubmit) {
        isValid = await gFormInstance.value.handleSubmit()
      } else {
        isValid = await gFormInstance.value.validate()
      }
      if (!isValid) return
      const requestData = await handlerComFn(handlerConfig.beforeSubmitFn, cloneDeep(gFormData.value))
      if (requestData === false) return
      gConfirmLoading.value = true
      let resData = null
      if (gIsEdit.value) {
        if (!apiFnConfig.edit || typeof apiFnConfig.edit !== 'function') {
          return console.error('apiFnConfig的edit属性未配置api函数')
        }
        resData = await apiFnConfig.edit(requestData)
      } else {
        if (!apiFnConfig.add || typeof apiFnConfig.add !== 'function') {
          return console.error('apiFnConfig的add属性未配置api函数')
        }
        resData = await apiFnConfig.add(requestData)
      }
      const isPass = await handlerComFn(handlerConfig.afterSubmitFn, resData)
      if (isPass === false) return
      proxy.$modal.msgSuccess(gIsEdit.value ? '修改成功' : '新增成功')
      gClose()
    } catch (error) {
      console.log(error)
    } finally {
      gConfirmLoading.value = false
    }
  }

  const gAllExposeOption = {
    gOpen,
    gClose,
    gSubmitForm,
    gFormInstance,
    gFormData,
    gFormRule,
    gConfirmLoading,
    gVisible,
    gTitle,
    gIsEdit
  }

  // 返回
  return {
    gAllExposeOption,
    ...gAllExposeOption
  }
}

/**
 * 提交表单hook函数
 * @param {object} options
 */
export const useSubmitFormHook = (options) => {}

/**
 * 分页hooks函数
 * @param {object} options
 */
export const useListHook = (options) => {
  const { init = true, gSearchForm = ref({}), listApiFn = null, beforeRequest = null, afterRequest = null, hasPage = true, fieldMap = {} } = options

  const { page: pageField = 'pageNum', pageSize: pageSizeField = 'pageSize', data: dataField = 'list', total: totalField = 'total' } = fieldMap

  const gLoadingStatus = ref(false)
  const gTotal = ref(0)
  const gTableData = ref([])

  let initPage = 1
  let initPageSize = 10
  const pageInfo = ref({})
  if (hasPage) {
    pageInfo.value = {
      [pageField]: initPage,
      [pageSizeField]: initPageSize
    }
    // 设置初页码和分页大小
    if (pageSizeField in gSearchForm.value) {
      initPageSize = gSearchForm.value[pageSizeField]
      pageInfo.value[pageSizeField] = gSearchForm.value[pageSizeField]
    }
    if (pageField in gSearchForm.value) {
      initPage = gSearchForm.value[pageField]
      pageInfo.value[pageField] = gSearchForm.value[pageField]
    }
  }
  // 记录初始表单
  const initSearchForm = cloneDeep(gSearchForm.value)

  // 核心数据(向外抛出)
  const fullParams = computed(() => ({
    gTableData: gTableData.value,
    gTotal: gTotal.value,
    pageInfo: pageInfo.value,
    gSearchForm: gSearchForm.value
  }))

  // 重置页码
  function gResetPage() {
    pageInfo.value[pageField] = initPage
    pageInfo.value[pageSizeField] = initPageSize
  }
  // 重置搜索表单
  function gResetSearchForm(data = {}, merge = true) {
    if (merge) {
      gSearchForm.value = mergeObj(cloneDeep(initSearchForm), data)
    } else {
      gSearchForm.value = data
    }
  }

  // 获取列表
  const gGetList = async () => {
    let query = {
      ...gSearchForm.value,
      ...pageInfo.value
    }
    console.log('queryqueryqueryqueryquery', query)
    const reqData = await handlerComFn(beforeRequest, cloneDeep(query))
    if (reqData === false) return
    try {
      gLoadingStatus.value = true
      if (!listApiFn || typeof listApiFn !== 'function') {
        return console.error('listApiFn属性未配置api函数')
      }
      const response = await listApiFn(reqData)
      const responseData = await handlerComFn(afterRequest, response.data)
      if (responseData === false) return
      gTableData.value = get(responseData, dataField, [])
      console.log('gTableData.value', gTableData.value)
      if (hasPage) {
        gTotal.value = get(responseData, totalField, 0)
      }
      gLoadingStatus.value = false
      return Promise.resolve(fullParams)
    } catch (e) {
      console.error(e?.message ?? e)
      gLoadingStatus.value = false
      return Promise.reject(e?.message ?? e)
    }
  }
  init && gGetList()

  // 分页改变事件
  function gPageChange({ page, pageSize }) {
    pageInfo.value[pageField] = page
    pageInfo.value[pageSizeField] = pageSize
    nextTick(() => gGetList())
  }

  // 重置事件
  function gReset(params = {}) {
    const { form = {}, merge = false } = params
    if (Object.keys(form).length) {
      gResetSearchForm(form, merge)
    }
    hasPage && gResetPage()
    gGetList()
  }
  // 搜索事件
  function gSearch() {
    if (hasPage) {
      pageInfo.value[pageField] = initPage
    }
    gGetList()
  }

  let gAllExposeOption = {
    hasPage,
    fieldMap: { pageField, pageSizeField, dataField, totalField }, // 字段映射
    gGetList, // 获取列表
    gLoadingStatus, // loading状态
    gTotal, // 总数
    gTableData, // 列表数据
    pageInfo, // 分页信息
    fullParams, // 全部参数
    gResetPage, // 重置页码
    gSearchForm, // 搜索表单
    gResetSearchForm, // 重置搜索表单
    gSearch, // 搜索
    gReset, // 重置(重置分页、搜索表单、获取列表)
    gPageChange // 分页改变事件
  }

  return {
    gAllExposeOption,
    ...gAllExposeOption
  }
}

/**
 * 删除hooks函数
 * @param {object} options
 */
export const useDelHook = (options) => {
  const { proxy } = getCurrentInstance()
  const { moduleName = '模块', delApiFn = null, beforeDelFn = null, afterDelFn = null } = options

  const gDelete = async (data, msg) => {
    if (!delApiFn || typeof delApiFn !== 'function') {
      return console.error('delApiFn属性未配置api函数')
    }
    await proxy.$modal.confirm(msg || `确认删除这些数据吗？`)
    const reqData = await handlerComFn(beforeDelFn, data)
    if (reqData === false) return
    delApiFn(reqData)
      .then(async (responseData) => {
        proxy.$modal.msgSuccess(`删除${moduleName}成功`)
        await handlerComFn(afterDelFn, responseData)
      })
      .catch((error) => {
        console.error(error)
      })
  }

  return {
    gDelete
  }
}
